#include <winsock2.h>
#include <interfacelib/frame/handlemanager.h>
#include <interfacelib/ime/ime.h>
#include <interfacelib/window/window.h>

using namespace interfacelib::IME;
IME::IME() : m_keyLayout( 0 ), m_imeProperty( 0 ), m_composedLength( 0 ), m_imc( 0 ), m_windowHandle( 0 )
{
	m_inputLanguageMode = ENABLE_INPUT_ENGLISH | ENABLE_INPUT_HANGUL;
}

IME::~IME()
{
}

/*
	FUNCTION:   - 
	RETURNS:    -
	PARAMETERS: -
	COMMENTS:   -
*/
void IME::initialize( interfacelib::Window::Window *window )
{
	m_windowHandle = interfacelib::Frame::HandleManager::getInstance()->getWindowHandle();
	m_parentWindow = window;
	m_keyLayout = GetKeyboardLayout( 0 );
	m_imeProperty = ImmGetProperty( m_keyLayout, IGP_PROPERTY );
}


bool IME::checkIMEStatus()
{
	return ( ( m_imeProperty & IME_PROP_SPECIAL_UI ) == 0 && ( m_imeProperty & IME_PROP_AT_CARET ) != 0 );
}

void IME::startIMEContext()
{
	m_imc = ImmGetContext( m_windowHandle );
}

void IME::finishIMEContext()
{
	ImmReleaseContext( m_windowHandle, m_imc );
	m_imc = NULL;
}

void IME::getString( LPTSTR str )
{
	{
		Synchronized_IME sync( this );

		DWORD stringLength = ImmGetCompositionString( m_imc, GCS_RESULTSTR, NULL, 0 );

		if ( stringLength > 0 )
		{
			ZeroMemory( str, sizeof( TCHAR ) * 5 );
			ImmGetCompositionString( m_imc, GCS_RESULTSTR, str, stringLength );

			stringLength = lstrlen( str );
			str[ stringLength ] = 0;
		}
	}
}

void IME::getString( LPTSTR str, long flag )
{
	{
		Synchronized_IME sync( this );

		DWORD stringLength = ImmGetCompositionString( m_imc, GCS_COMPSTR, NULL, 0 );

		if ( stringLength > 0 )
		{
			ZeroMemory( str, sizeof( TCHAR ) * 5 );
			::ImmGetCompositionString( m_imc, GCS_COMPSTR, str, stringLength );

			stringLength = lstrlen(str);
			str[ stringLength ] = 0;
			
			LPTSTR strAttr = NULL;

			if( flag & GCS_COMPATTR )
			{
				DWORD attrLength = ::ImmGetCompositionString( m_imc, GCS_COMPATTR, 0, 0 );
				if( attrLength > 0 )
				{
					strAttr = new TCHAR [ attrLength + 1 ];
					::ImmGetCompositionString( m_imc, GCS_COMPATTR, strAttr, attrLength );
					strAttr[ attrLength ] = 0;
				}
			}

			m_composedLength = ( int )stringLength;

			if ( strAttr ) delete strAttr;
		}
	}
}

void IME::onIMEStartComposition( WPARAM command, LPARAM data )
{
	if ( checkIMEStatus() == false ) return;

	m_composedLength = 0;

	m_imeState |= IME_IN_COMPOSITION;

}

void IME::onIMEEndComposition( WPARAM command, LPARAM data )
{
	if ( checkIMEStatus() == false ) return;

	m_composedLength = 0;

	m_imeState &= ~IME_IN_COMPOSITION;

}

void IME::onIMEComposition( WPARAM command, LPARAM data )
{
	if ( checkIMEStatus() == false ) return;

	TCHAR ch[20];
	ZeroMemory( ch, sizeof ( TCHAR ) * 20 );

	if ( data & GCS_RESULTSTR )
	{
		getString( ch );

		m_parentWindow->onUserIMEResultChar( ( WPARAM )ch, 0 );
	}
	else if ( data & GCS_COMPSTR )
	{
		getString( ch, data );

		m_parentWindow->onUserIMECompChar( ( WPARAM )ch, 0 );
	}

}

void IME::onIMECompositionFull( WPARAM command, LPARAM data )
{
}

void IME::onInputLangChange( WPARAM command, LPARAM data )
{
}

void IME::onIMESetContext( WPARAM command, LPARAM data )
{
	if ( m_imeProperty & IME_PROP_AT_CARET )
		data &= ~( ISC_SHOWUICOMPOSITIONWINDOW | ISC_SHOWUIALLCANDIDATEWINDOW );

	DefWindowProc( m_windowHandle, WM_IME_SETCONTEXT, command, data );
}

void IME::onIMENotify( WPARAM command, LPARAM data )
{
	if ( enableInputHangul() == false && enableInputEnglish() == false ) return;

	if ( command == IMN_SETCONVERSIONMODE )
	{
		if ( enableInputHangul() == false )
			setHangulMode( false );
		if ( enableInputEnglish() == false )
			setHangulMode( true );

	}
}

void IME::onIMEControl( WPARAM command, LPARAM data )
{
}

void IME::setCompositionFont( LPLOGFONT logFont )
{
}

void IME::setCompositionWndPos( POINT& point )
{
}

void IME::getCompositionCursorPos()
{
}

bool IME::preTranslateMessage( UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message )
	{ 
	case WM_IME_STARTCOMPOSITION :
		{
			onIMEStartComposition( wParam, lParam );
			return ( true );
		}

	case WM_IME_ENDCOMPOSITION :
		{
			onIMEEndComposition( wParam, lParam );
			return ( true );
		}

	case WM_IME_COMPOSITION :
		{
			onIMEComposition( wParam, lParam );
			return ( true );
		}

	case WM_IME_SETCONTEXT :
		{
			onIMESetContext( wParam, lParam );
			return ( true );
		}
	case WM_USER_IME_NOTIFY :
	case WM_IME_NOTIFY:	
		{
			onIMENotify( wParam, lParam );
			return ( true );
		}

	case WM_INPUTLANGCHANGE :
		{
			onInputLangChange( wParam, lParam );
			return ( true );
		}
	case WM_IME_CONTROL :
		{
			onIMEControl( wParam, lParam );
			return ( true );
		}
	case WM_IME_COMPOSITIONFULL :
		{
			onIMECompositionFull( wParam, lParam );	
			return ( true );
		}
    }

	return ( false );
}


bool IME::isHangulMode()
{
    bool isHangleMode = false;  

    {  
		Synchronized_IME sync( this );

        DWORD conversion, sentence;  

        if ( ImmGetConversionStatus( m_imc, &conversion, &sentence ) )
		{
            isHangleMode = ( conversion & IME_CMODE_NATIVE ? true : false );  
        }
    }  

    return ( isHangleMode );  

}

void IME::setHangulMode( bool isHangleMode )
{
	if ( isHangulMode() == isHangleMode ) return;
	{
		Synchronized_IME sync( this );

		ImmSetConversionStatus ( m_imc, ( isHangleMode == true ) ? IME_CMODE_HANGUL : IME_CMODE_ALPHANUMERIC, 0 );
	}
}

void IME::resetIME()
{
	{
		Synchronized_IME sync( this );

		ImmSetCompositionString( m_imc, SCS_SETSTR, NULL, 0, NULL, 0 );
	}
}

void IME::setEnableInputHangul( bool enableHangul )
{
	if ( enableHangul )
	{
		m_inputLanguageMode |= ENABLE_INPUT_HANGUL;
	}
	else
	{
		setHangulMode( false );
		m_inputLanguageMode &= ~ENABLE_INPUT_HANGUL;
	}
}

void IME::setEnableInputEnglish( bool enableEnglish )
{
	if ( enableEnglish )
	{
		m_inputLanguageMode |= ENABLE_INPUT_ENGLISH;
	}
	else
	{
		setHangulMode( true );
		m_inputLanguageMode &= ~ENABLE_INPUT_ENGLISH;
	}
}

bool IME::enableInputHangul()
{
	return ( ( ( m_inputLanguageMode & ENABLE_INPUT_HANGUL ) == ENABLE_INPUT_HANGUL ) ? true : false );
}
			
bool IME::enableInputEnglish()
{
	return ( ( ( m_inputLanguageMode & ENABLE_INPUT_ENGLISH ) == ENABLE_INPUT_ENGLISH ) ? true : false );
}